using System;
using System.Collections;
using System.IO;

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Utilities;

namespace Org.BouncyCastle.Cms
{
	/**
	* containing class for an CMS Authenticated Data object
	*/
	public class CmsAuthenticatedData
	{
		internal RecipientInformationStore recipientInfoStore;
		internal ContentInfo contentInfo;

		private AlgorithmIdentifier macAlg;
		private Asn1Set authAttrs;
		private Asn1Set unauthAttrs;
		private byte[] mac;

		public CmsAuthenticatedData(
			byte[] authData)
			: base(CmsUtilities.ReadContentInfo(authData))
		{
		}

		public CmsAuthenticatedData(
			Stream authData)
			: base(CmsUtilities.ReadContentInfo(authData))
		{
		}

		public CmsAuthenticatedData(
			ContentInfo contentInfo)
		{
			this.contentInfo = contentInfo;

			AuthenticatedData authData = AuthenticatedData.GetInstance(contentInfo.Content);

			//
			// read the encapsulated content info
			//
			ContentInfo encInfo = authData.GetEncapsulatedContentInfo();

			this.macAlg = authData.GetMacAlgorithm();
			this.mac = authData.GetMac().GetOctets();

			//
			// load the RecipientInfoStore
			//
			Asn1Set s = authData.GetRecipientInfos();
			IList infos = new ArrayList();
			byte[] contentOctets = Asn1OctetString.GetInstance(encInfo.Content).GetOctets();

			for (int i = 0; i != s.Count; i++)
			{
				RecipientInfo info = RecipientInfo.GetInstance(s[i]);
				MemoryStream contentStream = new MemoryStream(contentOctets, false);

				object type = info.Info;

				if (type is KeyTransRecipientInfo)
				{
					infos.Add(new KeyTransRecipientInformation(
						(KeyTransRecipientInfo)type, null, macAlg, contentStream));
				}
				else if (type is KEKRecipientInfo)
				{
					infos.Add(new KekRecipientInformation(
						(KekRecipientInfo)type, null, macAlg, contentStream));
				}
				else if (type is KeyAgreeRecipientInfo)
				{
					infos.Add(new KeyAgreeRecipientInformation(
						(KeyAgreeRecipientInfo)type, null, macAlg, contentStream));
				}
				else if (type is PasswordRecipientInfo)
				{
					infos.Add(new PasswordRecipientInformation(
						(PasswordRecipientInfo)type, null, macAlg, contentStream));
				}
			}

			this.authAttrs = authData.GetAuthAttrs();
			this.recipientInfoStore = new RecipientInformationStore(infos);
			this.unauthAttrs = authData.GetUnauthAttrs();
		}

		public byte[] GetMac()
		{
			return Arrays.Clone(mac);
		}

//		private byte[] encodeObj(
//			Asn1Encodable obj)
//		{
//			return obj == null ? null : obj.GetEncoded();
//		}

		public AlgorithmIdentifier MacAlgorithmID
		{
			get { return macAlg; }
		}

		/**
		* return the object identifier for the content MAC algorithm.
		*/
		public string MacAlgOid
		{
			get { return macAlg.ObjectID.Id; }
		}

//		/**
//		* return the ASN.1 encoded MAC algorithm parameters, or null if
//		* there aren't any.
//		*/
//		public byte[] getMacAlgParams()
//		{
//		try
//		{
//		return encodeObj(macAlg.getParameters());
//		}
//		catch (Exception e)
//		{
//		throw new RuntimeException("exception getting encryption parameters " + e);
//		}
//		}

//		/**
//		* Return an AlgorithmParameters object giving the MAC parameters
//		* used to digest the message content.
//		*
//		* @param provider the provider to generate the parameters for.
//		* @return the parameters object, null if there is not one.
//		* @throws org.bouncycastle.cms.CMSException if the algorithm cannot be found, or the parameters can't be parsed.
//		* @throws java.security.NoSuchProviderException if the provider cannot be found.
//		*/
//		public AlgorithmParameters getMacAlgorithmParameters(
//		String  provider)
//		throws CMSException, NoSuchProviderException
//		{
//		return getMacAlgorithmParameters(CMSUtils.getProvider(provider));
//		}
//
//		/**
//		* Return an AlgorithmParameters object giving the MAC parameters
//		* used to digest the message content.
//		*
//		* @param provider the provider to generate the parameters for.
//		* @return the parameters object, null if there is not one.
//		* @throws org.bouncycastle.cms.CMSException if the algorithm cannot be found, or the parameters can't be parsed.
//		*/
//		public AlgorithmParameters getMacAlgorithmParameters(
//		Provider provider)
//		throws CMSException
//		{
//		return CMSEnvelopedHelper.INSTANCE.getEncryptionAlgorithmParameters(getMacAlgOID(), getMacAlgParams(), provider);
//		}

		/**
		* return a store of the intended recipients for this message
		*/
		public RecipientInformationStore GetRecipientInfos()
		{
			return recipientInfoStore;
		}

		/**
		 * return the ContentInfo 
		 */
		public ContentInfo ContentInfo
		{
			get { return contentInfo; }
		}

		/**
		* return a table of the digested attributes indexed by
		* the OID of the attribute.
		*/
		public Asn1.Cms.AttributeTable GetAuthAttrs()
		{
			if (authAttrs == null)
				return null;

			return new Asn1.Cms.AttributeTable(authAttrs);
		}

		/**
		* return a table of the undigested attributes indexed by
		* the OID of the attribute.
		*/
		public Asn1.Cms.AttributeTable GetUnauthAttrs()
		{
			if (unauthAttrs == null)
				return null;

			return new Asn1.Cms.AttributeTable(unauthAttrs);
		}

		/**
		* return the ASN.1 encoded representation of this object.
		*/
		public byte[] GetEncoded()
		{
			return contentInfo.GetEncoded();
		}
	}
}
